package com.example.learn_spring_boot3.interecepror;

import com.example.learn_spring_boot3.annotation.PassToken;
import com.example.learn_spring_boot3.entity.User;
import com.example.learn_spring_boot3.exception.ServiceException;
import com.example.learn_spring_boot3.mapper.UserMapper;
import com.example.learn_spring_boot3.utils.JWTUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.method.HandlerMethod;

import java.lang.reflect.Method;

// 这里可以不用加 @Component 注解
// @Component
public class JWTInterceptor implements HandlerInterceptor {

    @Autowired
    private UserMapper userMapper;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        String requestURI = request.getRequestURI();
        // 直接放行特殊的接口
        if (requestURI.contains("/favicon.ico") || requestURI.contains("/error")) {
            return true;
        }

        // 从 http 请求头中取出 token
        String authorization = request.getHeader("Authorization");

        // 如果不是映射到方法直接通过
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        // 获取请求方法
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();

        // 检查是否有 PassToken注解, 有则跳过认证
        if (method.isAnnotationPresent(PassToken.class)) {
            PassToken passToken = method.getAnnotation(PassToken.class);
            if (passToken.required()) {
                return true;
            }
        }

        if (authorization == null) {
            throw new ServiceException(401, "无token，请重新登录");
        }

        try {
            Claims claims = JWTUtils.getClaimsFromToken(authorization);
            // System.out.println("claims = " + claims);

            Integer userId = claims.get("userId", Integer.class);
            // 去数据库中查询是否有该用户的信息
            User user = userMapper.selectById(userId);

            if (user == null) {
                throw new ServiceException(401, "用户不存在, 请重新登录");
            }
        } catch (ExpiredJwtException err) {
            err.printStackTrace();
            throw new ServiceException(401, "权限不足");
        }

        return true;
    }
}
